﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Fighter.GameContent;
using Fighter.Screens;

namespace Fighter
{
    /// <summary>
    /// Facing direction along the X axis.
    /// </summary>
    enum FaceDirection
    {
        Left = -1,
        Right = 1,
    }

    /// <summary>
    /// A monster who is impeding the progress of our fearless adventurer.
    /// </summary>
    class Enemy
    {
        public Level Level
        {
            get { return level; }
        }
        Level level;

        /// <summary>
        /// Position in world space of the bottom center of this enemy.
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// FLOAT : Nombre de px qu'il reste à reculer. Définit par un Hit subit
        /// </summary>
        private float recoilByHit;
        private const float recoilVelocity = 20;
        public void iveBeenHit(float how)
        {
            //position.X = position.X + how;
            this.recoilByHit = how;
        }

        protected Vector2 position;

        protected Rectangle localBounds;
        /// <summary>
        /// Gets a rectangle which bounds this enemy in world space.
        /// </summary>
        public Rectangle BoundingRectangle
        {
            get
            {
                int left = (int)Math.Round(Position.X - sprite.Origin.X) + localBounds.X;
                int top = (int)Math.Round(Position.Y - sprite.Origin.Y) + localBounds.Y;

                return new Rectangle(left, top, localBounds.Width, localBounds.Height);
            }
        }

        //life of the monster
        private int life = 1;
        public int Life
        {
            get { return life; }
            set { life = value; }
        }
        // Animations
        private Animation runAnimation;
        private Animation idleAnimation;
        private AnimationPlayer sprite;

        /// <summary>
        /// The direction this enemy is facing and moving along the X axis.
        /// </summary>
        public FaceDirection Direction
        {
            get { return direction; }
            set { direction = value; }
        }
        protected FaceDirection direction = FaceDirection.Left;

        /// <summary>
        /// How long this enemy has been waiting before turning around.
        /// </summary>
        protected float waitTime;

        /// <summary>
        /// How long to wait before turning around.
        /// </summary>
        protected const float MaxWaitTime = 0.5f;

        /// <summary>
        /// Vitesse normale d'un ennemi.
        /// </summary>
        public const float MoveSpeed = 128.0f;

        /// <summary>
        /// Vitesse pendant un sprint.
        /// </summary>
        public const float SprintSpeed = 256.0f;

        /// <summary>
        /// The speed at which this enemy moves along the X axis.
        /// </summary>
        public float ActualMoveSpeed
        {
            get { return actualMoveSpeed; }
            set { actualMoveSpeed = value; }
        }
        private float actualMoveSpeed = 128.0f;

        protected GraphicsDeviceManager graphics;

        protected bool isAgressive = true;
        public bool IsAgressive
        {
            get { return isAgressive; }
            set { isAgressive = value; }
        }
        protected bool isMoving = true;
        public bool IsMoving
        {
            get { return isMoving; }
            set { isMoving = value; }
        }
        private int distanceBeforeRush = 200;
        public int DistanceBeforeRush
        {
            get { return distanceBeforeRush; }
            set { distanceBeforeRush = value; }
        }

        /// <summary>
        /// Constructs a new Enemy.
        /// </summary>
        public Enemy(Level level, Vector2 position, string spriteSet, GraphicsDeviceManager graphics, int life)
        {
            this.level = level;
            this.position = position;
            this.graphics = graphics;
            this.life = life;

            LoadContent(spriteSet);
        }

        /// <summary>
        /// Loads a particular enemy sprite sheet and sounds.
        /// </summary>
        public void LoadContent(string spriteSet)
        {
            // Load animations.
            spriteSet = "Sprites/" + spriteSet + "/";
            runAnimation = new Animation(Level.Content.Load<Texture2D>(spriteSet + "Run"), 0.1f, true);
            idleAnimation = new Animation(Level.Content.Load<Texture2D>(spriteSet + "Idle"), 0.15f, true);
            sprite.PlayAnimation(idleAnimation);

            // Calculate bounds within texture size.
            int width = (int)(idleAnimation.FrameWidth * 0.35 * GameplayScreen.baseScreenSize.X / (float)graphics.GraphicsDevice.PresentationParameters.BackBufferWidth);
            int left = (idleAnimation.FrameWidth - width) / 2;
            int height = (int)(idleAnimation.FrameWidth * 0.7 * GameplayScreen.baseScreenSize.Y / (float)graphics.GraphicsDevice.PresentationParameters.BackBufferHeight);
            int top = idleAnimation.FrameHeight - height;
            localBounds = new Rectangle(left, top, width, height);
        }

        /// <summary>
        /// Paces back and forth along a platform, waiting at either end.
        /// </summary>
        public virtual void Update(GameTime gameTime)
        {
            if (isMoving)
            {
                float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

                // Calculate tile position based on the side we are walking towards.
                float posX = Position.X + localBounds.Width / 2 * (int)direction;
                int tileX = (int)Math.Floor(posX / Tile.Width) - (int)direction;
                int tileY = (int)Math.Floor(Position.Y / Tile.Height);

                if (waitTime > 0)
                {
                    // Wait for some amount of time.
                    waitTime = Math.Max(0.0f, waitTime - (float)gameTime.ElapsedGameTime.TotalSeconds);
                    if (waitTime <= 0.0f)
                    {
                        // Then turn around.
                        direction = (FaceDirection)(-(int)direction);
                    }
                }
                else
                {
                    // If we are about to run into a wall or off a cliff, start waiting.
                    if (Level.GetCollision(tileX + (int)direction, tileY - 4) == TileCollision.Impassable ||
                        Level.GetCollision(tileX + (int)direction, tileY - 3) == TileCollision.Impassable ||
                        Level.GetCollision(tileX + (int)direction, tileY - 2) == TileCollision.Impassable ||
                        Level.GetCollision(tileX + (int)direction, tileY - 1) == TileCollision.Impassable ||
                        Level.GetCollision(tileX + (int)direction, tileY) == TileCollision.Passable)
                    {
                        waitTime = MaxWaitTime;
                    }
                    else
                    {
                        // Move in the current direction.
                        Vector2 velocity = new Vector2((int)direction * actualMoveSpeed * elapsed, 0.0f);
                        position = position + velocity;
                    }
                }
            }
        }

        /// <summary>
        /// Draws the animated enemy.
        /// </summary>
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            if (waitTime > 0)
            {
                sprite.PlayAnimation(idleAnimation);
            }
            else
            {
                sprite.PlayAnimation(runAnimation);
            }

            // Draw facing the way the enemy is moving.
            SpriteEffects flip = direction > 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None;

            if (this.recoilByHit != 0 )
            {
                if (this.recoilByHit > recoilVelocity)
                {
                    
                    position.X += recoilVelocity;
                    this.recoilByHit -= recoilVelocity;
                }
                else
                {
                    position.X += this.recoilByHit;
                    this.recoilByHit = 0;
                }
            }   

            sprite.Draw(gameTime, spriteBatch, position, flip);
        }
    }
}